package web.reports.action;

import com.opensymphony.xwork2.ActionSupport;
import domain.entities.Advancedfinalstudyreports;
import domain.entities.Centro;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
import services.ProtocolCRUDService;
import services.SiteLevelDocumentsService;
import services.exceptions.NoProtocoloCompromisopaisSelectedException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: nico
 * Date: 09/10/12
 * Time: 13:53
 * To change this template use File | Settings | File Templates.
 */
@Namespace("/Reports/ReporteTDS")
public class ReporteTDSController extends ActionSupport {

    private SiteLevelDocumentsService siteLevelDocumentsService;
    private ProtocolCRUDService protocolCRUDService;
    private InputStream excelStream;
    private String filename;
    private int contentLength;
    private int rowCount;
    private float count;
    private float cargadas;
    private ArrayList<Integer> rowTitulos;

    @Autowired
    public ReporteTDSController(SiteLevelDocumentsService siteLevelDocumentsService, ProtocolCRUDService protocolCRUDService) {
        this.siteLevelDocumentsService = siteLevelDocumentsService;
        this.protocolCRUDService = protocolCRUDService;
        rowTitulos = new ArrayList<Integer>(0);
    }

    @Action(value="main", results={
            @Result(name="success",location="/reports.reportetds.tiles", type="tiles")
    })
    public String execute() throws NoProtocoloCompromisopaisSelectedException {
        return SUCCESS;
    }

    @Action(value="download", results={
            @Result(name="success",type="stream",
                    params = {  "contentType", "application/vnd.ms-excel",
                                "inputName", "excelStream",
                                "contentDisposition", "attachment; filename=${filename}",
                                "bufferSize", "1024",
                                "contentLength", "${contentLength}"
                    })
    })
    public String download() throws NoProtocoloCompromisopaisSelectedException, IOException {
        this.setFilename("ReporteTds.xls");
        crearReporte();
        return SUCCESS;
    }


    private void crearReporte() throws NoProtocoloCompromisopaisSelectedException, IOException {
        ArrayList<Centro> sites = protocolCRUDService.findSitesByProtocol(protocolCRUDService.recoverProtocoloCompromisopais());
        Workbook wb = new HSSFWorkbook();

        HSSFCellStyle styleTitulos = (HSSFCellStyle) wb.createCellStyle();
        HSSFCellStyle styleHeader = (HSSFCellStyle) wb.createCellStyle();
        HSSFCellStyle styleObjects = (HSSFCellStyle) wb.createCellStyle();
        HSSFFont hSSFFont = (HSSFFont) wb.createFont();

        createStyles(styleHeader, styleTitulos, styleObjects, hSSFFont);

        for(Centro c : sites){
            Sheet hoja = wb.createSheet(c.getInstitucion());
            hoja.setDefaultColumnWidth(18);

            header(hoja, c, styleHeader, styleTitulos, styleObjects);
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        wb.write(baos);
        ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray());
        setExcelStream(bis);
        contentLength = baos.size();

        return;
    }

    private void createStyles(HSSFCellStyle styleHeader, HSSFCellStyle styleTitulos, HSSFCellStyle styleObjects, HSSFFont hSSFFont) {

        hSSFFont.setFontName(HSSFFont.FONT_ARIAL);
        hSSFFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        hSSFFont.setColor(HSSFColor.WHITE.index);

        styleHeader.setFillPattern(CellStyle.SOLID_FOREGROUND);
        styleHeader.setFillBackgroundColor(HSSFColor.BLACK.index);
        styleHeader.setFont(hSSFFont);

        styleTitulos.setFillPattern(CellStyle.SOLID_FOREGROUND);
        styleTitulos.setFillBackgroundColor(HSSFColor.BLACK.index);
        styleTitulos.setFont(hSSFFont);
        styleTitulos.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        styleTitulos.setAlignment(CellStyle.ALIGN_CENTER);
        styleTitulos.setWrapText(true);
        styleTitulos.setBorderBottom(CellStyle.BORDER_THIN);
        styleTitulos.setBottomBorderColor(HSSFColor.WHITE.index);
        styleTitulos.setBorderTop(CellStyle.BORDER_THIN);
        styleTitulos.setTopBorderColor(HSSFColor.WHITE.index);
        styleTitulos.setBorderRight(CellStyle.BORDER_THIN);
        styleTitulos.setRightBorderColor(HSSFColor.WHITE.index);
        styleTitulos.setBorderLeft(CellStyle.BORDER_THIN);
        styleTitulos.setLeftBorderColor(HSSFColor.WHITE.index);

        styleObjects.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        styleObjects.setAlignment(CellStyle.ALIGN_CENTER);
        styleObjects.setBorderBottom(CellStyle.BORDER_THIN);
        styleObjects.setBottomBorderColor(HSSFColor.BLACK.index);
        styleObjects.setBorderTop(CellStyle.BORDER_THIN);
        styleObjects.setTopBorderColor(HSSFColor.BLACK.index);
        styleObjects.setBorderRight(CellStyle.BORDER_THIN);
        styleObjects.setRightBorderColor(HSSFColor.BLACK.index);
        styleObjects.setBorderLeft(CellStyle.BORDER_THIN);
        styleObjects.setLeftBorderColor(HSSFColor.BLACK.index);

        return;
    }

    private void header(Sheet hoja, Centro site, HSSFCellStyle styleHeader, HSSFCellStyle styleTitulos, HSSFCellStyle styleObjects){

        Row row = hoja.createRow(0);
        Cell cell1 = row.createCell(0);
        cell1.setCellValue("Site");
        cell1.setCellStyle(styleHeader);
        cell1 = row.createCell(1);
        cell1.setCellValue(site.getInstitucion());

        row = hoja.createRow(1);
        cell1 = row.createCell(0);
        cell1.setCellValue("Completed");
        cell1.setCellStyle(styleHeader);
        cell1 = row.createCell(1);
        DecimalFormat df = new DecimalFormat("###.##%");
        cell1.setCellValue(df.format(this.calcularPorcentajeTotal(site.getId(), hoja, styleTitulos, styleObjects, styleHeader)));

        hoja.addMergedRegion(new CellRangeAddress(0,0,1,3));

        for(Integer rowNumber : rowTitulos){
            hoja.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, 2));
        }

        return;
    }

    private float calcularPorcentajeTotal(Integer siteId, Sheet hoja, HSSFCellStyle styleTitulos, HSSFCellStyle styleObjects, HSSFCellStyle styleHeader){
        this.setCount(0);
        this.setCargadas(0);
        this.content(hoja, styleTitulos, styleObjects, styleHeader,
                siteLevelDocumentsService.findProtocolInformationBySiteId(siteId),
                siteLevelDocumentsService.findInformedConsentsBySiteId(siteId),
                siteLevelDocumentsService.findPrintedMaterialsBySiteId(siteId),
                siteLevelDocumentsService.findDataSafetyReportsBySiteId(siteId),
                siteLevelDocumentsService.findReaprobacionesBySiteId(siteId),
                siteLevelDocumentsService.findCtagBySiteId(siteId),
                siteLevelDocumentsService.findStudyStaffBySiteId(siteId),
                siteLevelDocumentsService.findStudydeviationsBySiteId(siteId),
                siteLevelDocumentsService.findSuplementalcrfcspBySiteId(siteId),
                siteLevelDocumentsService.findSaesBySiteId(siteId),
                siteLevelDocumentsService.findAdvancedfinalstudyreportsBySiteId(siteId),
                siteLevelDocumentsService.findSecdiscrepancyreportBySiteId(siteId));
        if(count > 0)
            return cargadas/count;
        else
            return 0;
    }

    private void content(Sheet hoja, HSSFCellStyle styleTitulos, HSSFCellStyle styleObjects, HSSFCellStyle styleHeader, List<? extends Object>... listas){
        this.rowCount = 4;

        if(listas.length == 0){
            Row r = hoja.createRow(rowCount);
            rowCount++;
            Cell c = r.createCell(0);
            c.setCellValue("No documents for this site.");
            return;
        }

        for(List objetos : listas){
            if(!objetos.isEmpty()){
                Class clase = objetos.get(0).getClass();

                Field[] fields = clase.getDeclaredFields();

                List<Object> fefyms = new ArrayList<Object>(0);
                if(clase.equals(Advancedfinalstudyreports.class)){
                    fefyms = getFefyms(clase, objetos);
                }

                String classTitle = getClassTitle(fields, objetos.get(0));

                Row row = hoja.createRow(rowCount);
                rowTitulos.add(rowCount);
                rowCount++;
                Cell cell = row.createCell(0);
                cell.setCellValue(classTitle);
                cell.setCellStyle(styleHeader);

                LinkedHashMap<String, String> titulos = titulos(fields, objetos.get(0), hoja, styleTitulos);

                for(Object o : objetos){
                    try {
                        row = hoja.createRow(rowCount);
                        rowCount++;
                        int column = 0;
                        for(String key: titulos.keySet()){
                            Field field = getFieldByName(fields, key);
                            Cell cell1 = row.createCell(column);
                            field.setAccessible(true);
                            String value = field.get(o) != null ? String.valueOf(field.get(o)) : "-";
                            if(value.equals("true"))
                                value = "True";
                            else if(value.trim().isEmpty())
                                value = "-";
                            cell1.setCellValue(value);
                            cell1.setCellStyle(styleObjects);
                            column++;
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                }
                contarFechas(fields, objetos);
                rowCount++;
                if(fefyms.size()>0){
                    addFefyms(fefyms, hoja, styleHeader, styleObjects, styleTitulos, fields);
                }
            }
        }
        return;
    }

    private String getClassTitle(Field[] fields, Object o) {
        try {
            for(Field f : fields){
                f.setAccessible(true);
                if(f.getName().equals("CLASSTITLE"))
                    return (String) f.get(o);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private LinkedHashMap<String, String> titulos(Field[] fields, Object o, Sheet hoja, HSSFCellStyle style){
        LinkedHashMap<String, String> titulos = null;
        try {
            for(Field f : fields){
                f.setAccessible(true);
                if(f.getName().equals("TITULOS"))
                        titulos = (LinkedHashMap<String, String>) f.get(o);
            }
            if(titulos != null){
                ArrayList<String> titulosValues = new ArrayList<String>(titulos.values());
                Row row=hoja.createRow(rowCount);
                rowCount++;
                row.setHeightInPoints(55.62f); //1.68cm
                int column = 0;
                for(Field field : fields){
                    if(titulosValues.size() > column){
                        Cell cell = row.createCell(column);
                        cell.setCellStyle(style);
                        cell.setCellValue(titulosValues.get(column));
                        column++;
                    }
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return titulos;
    }


    private void contarFechas(Field[] fields, List<Object> objetos){
        for (Field field : fields) {
            if(Date.class.isAssignableFrom(field.getType())){
                for(Object o : objetos){
                    count++;
                    try {
                        field.setAccessible(true);
                        if(field.get(o) != null){
                            cargadas++;
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return;
    }

    private Field getFieldByName(Field[] fields, String name) throws NoSuchFieldException {
        for(Field f : fields){
            if(f.getName().equals(name)){
                return f;
            }
        }
        System.out.println("lalala name --> " + name);
        throw new NoSuchFieldException();
    }


    //FEFYM ONLY////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    private void addFefyms(List<Object> fefyms, Sheet hoja, HSSFCellStyle styleHeader, HSSFCellStyle styleObjects, HSSFCellStyle styleTitulos, Field[] fields) {
        String classTitle = getClassTitle(fields, fefyms.get(0)) + " - FEFYM Only";

        Row row = hoja.createRow(rowCount);
        rowTitulos.add(rowCount);
        rowCount++;
        Cell cell = row.createCell(0);
        cell.setCellValue(classTitle);
        cell.setCellStyle(styleHeader);

        LinkedHashMap<String, String> titulos = new LinkedHashMap<String, String>(0);
        titulos.put("report", "Report");
        titulos.put("deadline", "Deadline");
        titulos.put("dateReceivedBms", "Date Received at BMS");
        titulos.put("submissionExternalEc", "Submission External EC");

        if(titulos != null){
            ArrayList<String> titulosValues = new ArrayList<String>(titulos.values());
            Row rowTitle=hoja.createRow(rowCount);
            rowCount++;
            rowTitle.setHeightInPoints(55.62f); //1.68cm
            int column = 0;
            for(Field field : fields){
                if(titulosValues.size() > column){
                    Cell cellTitle = rowTitle.createCell(column);
                    cellTitle.setCellStyle(styleTitulos);
                    cellTitle.setCellValue(titulosValues.get(column));
                    column++;
                }
            }
        }

        for(Object o : fefyms){
            try {
                row = hoja.createRow(rowCount);
                rowCount++;
                int column = 0;
                for(String key: titulos.keySet()){
                    Field field = getFieldByName(fields, key);
                    Cell cell1 = row.createCell(column);
                    field.setAccessible(true);
                    String value = field.get(o) != null ? String.valueOf(field.get(o)) : "-";
                    if(value.equals("true"))
                        value = "True";
                    cell1.setCellValue(value);
                    cell1.setCellStyle(styleObjects);
                    column++;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        contarFechas(fields, fefyms);
        rowCount++;
    }

    private List<Object> getFefyms(Class clase, List objetos) {
        ArrayList<Object> fefyms = new ArrayList<Object>(0);
        Iterator iterator = objetos.iterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            try {
                Field field = clase.getDeclaredField("fefym");
                field.setAccessible(true);
                if(field.getBoolean(o)){
                    fefyms.add(o);
                    iterator.remove();
                }
            } catch (Exception e) { e.printStackTrace();}
        }
        return fefyms;
    }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public int getContentLength() {
        return contentLength;
    }

    public void setContentLength(int contentLength) {
        this.contentLength = contentLength;
    }

    public InputStream getExcelStream() {
        return excelStream;
    }

    public void setExcelStream(InputStream excelStream) {
        this.excelStream = excelStream;
    }

    public void setCount(float count) {
        this.count = count;
    }

    public void setCargadas(float cargadas) {
        this.cargadas = cargadas;
    }

    public int getRowCount() {
        return rowCount;
    }

    public void setRowCount(int rowCount) {
        this.rowCount = rowCount;
    }
}
